package io.gitee.cofenghen.jdbctempleplus.RowMapper;

import io.gitee.cofenghen.jdbctempleplus.support.EntityMeta;
import io.gitee.cofenghen.jdbctempleplus.support.EntityParser;
import io.gitee.cofenghen.jdbctempleplus.support.FieldMeta;
import org.springframework.beans.*;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

public class CustomBeanPropertyRowMapper <T> extends BeanPropertyRowMapper<T> {
    private Class<T> mappedClass;
    private EntityMeta entityMeta;
    public CustomBeanPropertyRowMapper(Class<T> mappedClass) {
        this.mappedClass=mappedClass;
        this.initialize(mappedClass);
    }

    protected T constructMappedInstance(ResultSet rs, TypeConverter tc) throws SQLException {
        Assert.state(this.mappedClass != null, "Mapped class was not specified");
        return BeanUtils.instantiateClass(this.mappedClass);
    }
    protected void initialize(Class<T> mappedClass) {
        // 先从缓存获取

         entityMeta= EntityParser.parse(mappedClass);




    }

    public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.initBeanWrapper(bw);
        T mappedObject = this.constructMappedInstance(rs, bw);
        bw.setBeanInstance(mappedObject);
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();
        Set<String> populatedProperties = this.isCheckFullyPopulated() ? new HashSet() : null;

        for(int index = 1; index <= columnCount; ++index) {
            String column = JdbcUtils.lookupColumnName(rsmd, index);
            String property = this.lowerCaseName(StringUtils.delete(column, " "));
            var  pd = this.entityMeta != null ? (FieldMeta)this.entityMeta.getDataFieldMeta(column.toLowerCase()) : null;
            if (pd != null) {
                try {
                    Object value = this.getColumnValue(rs, index, pd);
                    if (rowNumber == 0 && this.logger.isDebugEnabled()) {
                        this.logger.debug("Mapping column '" + column + "' to property '" + pd.getColumnName() + "' of type '" + ClassUtils.getQualifiedName(pd.getPropertyType()) + "'");
                    }

                    try {
                        bw.setPropertyValue(pd.getName(), value);
                    } catch (TypeMismatchException var15) {
                        if (value != null || !this.isPrimitivesDefaultedForNullValue()) {
                            throw var15;
                        }

                        if (this.logger.isDebugEnabled()) {
                            String propertyType = ClassUtils.getQualifiedName(pd.getPropertyType());
                            this.logger.debug("Ignoring intercepted TypeMismatchException for row %d and column '%s' with null value when setting property '%s' of type '%s' on object: %s\"\n".formatted(new Object[]{rowNumber, column, pd.getName(), propertyType, mappedObject}), var15);
                        }
                    }


                } catch (NotWritablePropertyException var16) {
                    throw new DataRetrievalFailureException("Unable to map column '" + column + "' to property '" + pd.getName() + "'", var16);
                }
            }
        }

        return mappedObject;
    }
    @Nullable
    protected Object getColumnValue(ResultSet rs, int index, FieldMeta pd) throws SQLException {
        return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
    }
}
